﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Carto;
using System.Threading;
using System.Windows.Forms;


namespace ConnectWithR 
{
    ///<summary>
    ///Class to control the precipitation data downloading!
    ///</summary>
    class PrecipitationManager: Downloador, SiteInfoInsertor
    {
        precipitation.WaterOneFlowClient ws;// precipitation WaterOneFlow web service client.

        public PrecipitationManager(precipitation.WaterOneFlowClient ws)
        {
            this.ws = ws;
        }

        /// <summary>
        /// download precipitation data
        /// </summary>
        /// <param name="siteLayer">layer of selected sites</param>
        /// <param name="pTable">time series table</param>
        /// <param name="startDate">start date</param>
        /// <param name="endDate">end date</param>
        /// <param name="pField">filed represented site code</param>
        /// <returns>time series table</returns>
        public ESRI.ArcGIS.Geodatabase.ITable downloadData(ESRI.ArcGIS.Carto.IFeatureLayer siteLayer, ESRI.ArcGIS.Geodatabase.ITable pTable, DateTime startDate, DateTime endDate, ESRI.ArcGIS.Geodatabase.IField pField)
        {
            int index = -1;
            String value = "";
            ICursor insertCursor = pTable.Insert(true);
            IRowBuffer iRowBuf = pTable.CreateRowBuffer();
            IFeatureSelection ifs = (IFeatureSelection)siteLayer;
            ISelectionSet iss = ifs.SelectionSet;
            String start = startDate.ToString("yyyy-MM-dd");
            String end = endDate.AddDays(1).ToString("yyyy-MM-dd");
            if (iss.Count == 0)
            {
                IFeatureCursor iCursor = siteLayer.Search(null, false);
                IFeature iFeature = iCursor.NextFeature();
                while (iFeature != null && pTable != null)
                {
                    index = iFeature.Fields.FindField(pField.Name);
                    value = Convert.ToString(iFeature.get_Value(index));
                    downloadTimeSeriesData(ws, start, end, value, pTable, insertCursor, iRowBuf);
                    iFeature = iCursor.NextFeature();
                }
                return pTable;
            }
            IEnumIDs selectedIDs = null;
            IFeature iSelectedFeature = null;
            IFeatureClass iFeaClassEntire = siteLayer.FeatureClass;
            selectedIDs = iss.IDs;
            int oid = selectedIDs.Next();
            while (oid != -1)
            {
                iSelectedFeature = iFeaClassEntire.GetFeature(oid);
                index = iSelectedFeature.Fields.FindField(pField.Name);
                value = Convert.ToString(iSelectedFeature.get_Value(index));
                downloadTimeSeriesData(ws, start, end, value, pTable, insertCursor, iRowBuf);
                oid = selectedIDs.Next();
            }
            return pTable;
        }

        /// <summary>
        /// insert the station info to the table
        /// </summary>
        /// <param name="pTable">station info table</param>
        /// <param name="preNetWork">string presented data type</param>
        /// <returns>station table</returns>
        public ESRI.ArcGIS.Geodatabase.ITable insertSiteInfo(ESRI.ArcGIS.Geodatabase.ITable pTable, string preNetWork)
        {
            ICursor insertCursor = pTable.Insert(true);
            IRowBuffer iRowBuf = pTable.CreateRowBuffer();
            precipitation.SiteInfoResponseTypeSite[] sites = getPrecipitationSites(ws);
            precipitation.SiteInfoType siteInfo = null;
            precipitation.LatLonPointType geoLocation = null;
            double x = 0.0000;
            double y = 0.0000;
            precipitation.SiteInfoTypeSiteCode sitsc = null;
            string siteCode = "";

            for (int i = 0; i < sites.Length; i++)
            {
                siteInfo = sites[i].siteInfo;
                geoLocation = (precipitation.LatLonPointType)siteInfo.geoLocation.geogLocation;
                x = geoLocation.latitude;
                y = geoLocation.longitude;
                sitsc = siteInfo.siteCode[0];
                siteCode = preNetWork + sitsc.Value;
                insertRow(pTable, i, x, y, siteCode, insertCursor, iRowBuf);
            }
            return pTable;
        }

        private static precipitation.SiteInfoResponseTypeSite[] getPrecipitationSites(precipitation.WaterOneFlowClient ws)
        {
            String[] emptyArray = { };
            MessageForm msgForm = new MessageForm();
            new Thread((ThreadStart)delegate
            {
                System.Windows.Forms.Application.Run(msgForm);
            }).Start();
            precipitation.SiteInfoResponseType sir = ws.GetSitesObject(emptyArray, "");
            precipitation.SiteInfoResponseTypeSite[] sites = sir.site;
            msgForm.Invoke((EventHandler)delegate { msgForm.Close(); });
            return sites;
        }

        private static ITable insertRow(ITable pTable, int fid, double x, double y, String siteInfo, ICursor insertCursor, IRowBuffer iRowBuf)
        {

            int oidIndex = pTable.FindField(pTable.OIDFieldName);
            int fidIndex = pTable.FindField("FID_");
            int xIndex = pTable.FindField("X");
            int yIndex = pTable.FindField("Y");
            int siteCode = pTable.FindField("siteCode");

            iRowBuf.set_Value(fidIndex, fid);
            iRowBuf.set_Value(xIndex, x);
            iRowBuf.set_Value(yIndex, y);
            iRowBuf.set_Value(siteCode, siteInfo);

            insertCursor.InsertRow(iRowBuf);
            return pTable;

        }

        private static ITable insertRow(ITable pTable, String siteCode, String TSTypeID, String TSDateTime, String TSUnit, Double TSValue, ICursor insertCursor, IRowBuffer iRowBuf)
        {
            int TSValueIndex = pTable.FindField("TSValue");
            int SiteCodeIndex = pTable.FindField("SiteCode");
            int TSTypeIDIndex = pTable.FindField("TSTypeID");
            int TSDateTimeIndex = pTable.FindField("TSDateTime");
            int TSUnitIndex = pTable.FindField("TSUnit");

            iRowBuf.set_Value(TSValueIndex, TSValue);
            iRowBuf.set_Value(SiteCodeIndex, siteCode);
            iRowBuf.set_Value(TSTypeIDIndex, TSTypeID);
            iRowBuf.set_Value(TSDateTimeIndex, TSDateTime);
            iRowBuf.set_Value(TSUnitIndex, TSUnit);

            insertCursor.InsertRow(iRowBuf);
            return pTable;
        }

        private static void downloadTimeSeriesData(precipitation.WaterOneFlowClient ws, string startDate, string endDate, string siteCode, ITable pTable, ICursor insertCursor, IRowBuffer iRowBuf)
        {
            String variableCode = "GHCN:8";
            MessageForm msgForm = new MessageForm();
            msgForm.lblMessage.Text = "Downloading data from site: " + siteCode;
            new Thread((ThreadStart)delegate
            {
                System.Windows.Forms.Application.Run(msgForm);
            }).Start();
            Double TSValue;
            String date;
            precipitation.VariablesResponseType vResponse = new precipitation.VariablesResponseType();
            vResponse = ws.GetVariableInfoObject(variableCode, "");
            String TSUnit = vResponse.variables[0].unit.unitName;
            precipitation.TimeSeriesResponseType tsResponse = new precipitation.TimeSeriesResponseType();

            try
            {
                tsResponse = ws.GetValuesObject(siteCode, variableCode, startDate, endDate, "");
            }
            catch (System.ServiceModel.FaultException ex1)
            {
                MessageBox.Show("Please check the date and sitecode field you chose first. Or there may be no data for the time you chose.");
                return;
            }
            finally
            {
                msgForm.Invoke((EventHandler)delegate { msgForm.Close(); });
            }

            precipitation.TimeSeriesType temp = (precipitation.TimeSeriesType)tsResponse.timeSeries.GetValue(0);
            precipitation.ValueSingleVariable[] values = temp.values[0].value;

            for (int i = 0; i < values.Length; i++)
            {
                TSValue = Convert.ToDouble(values[i].Value);
                if (TSValue < 0 || TSValue > 1000)
                {
                    TSValue = 0;
                }
                date = values[i].dateTime.ToString("s");
                insertRow(pTable, siteCode, variableCode, date, TSUnit, TSValue, insertCursor, iRowBuf);
            }

        }
    }
}
